{# ----------------------------------------------------------------------------
 # SymForce - Copyright 2022, Skydio, Inc.
 # This source code is under the Apache 2.0 license found in the LICENSE file.
 # ---------------------------------------------------------------------------- #}

{%- import "../util/util.jinja" as util with context -%}

#include "./{{ camelcase_to_snakecase(cls.__name__) }}.h"

// Camera operation implementations
namespace sym {

{% for spec in specs['CameraOps'] %}
template <typename Scalar>
{{ util.function_declaration_custom_namespace(spec, cls.__name__ + "<Scalar>", is_declaration=False) }} const {
    {{ util.expr_code(spec) -}}
}

{% endfor %}

// Print implementations
{% for scalar in scalar_types %}
std::ostream& operator<<(std::ostream& os, const {{ cls.__name__ }}{{ scalar[0] }}& a) {
    const Eigen::IOFormat fmt(Eigen::StreamPrecision, Eigen::DontAlignCols, ", ", "\n", "[", "]");
    os << "<{{ cls.__name__ }}{{ scalar[0] }} " << a.Data().transpose().format(fmt) << ">";
    return os;
}

{% endfor %}

}  // namespace sym

{# {% for scalar in scalar_types %}
extern template struct sym::{{ camelcase_to_snakecase(cls.__name__) }}::StorageOps<{{ scalar }}>;
extern template struct sym::{{ camelcase_to_snakecase(cls.__name__) }}::GroupOps<{{ scalar }}>;
extern template struct sym::{{ camelcase_to_snakecase(cls.__name__) }}::LieGroupOps<{{ scalar }}>;
extern template struct sym::StorageOps<{{ scalar }}>;
{% endfor %} #}

// Concept implementations for this class
#include "./ops/{{ camelcase_to_snakecase(cls.__name__) }}/storage_ops.h"

// Explicit instantiation
{% for scalar in scalar_types %}
template class sym::{{ cls.__name__ }}<{{ scalar }}>;
{% endfor %}
